#ifndef __NODO_ARBOL_BINARIO_H__
#define __NODO_ARBOL_BINARIO_H__

template <class T> class NodoArbolBinario {

private:

	T dato;
	NodoArbolBinario<T>* hijoIzquierdo;
	NodoArbolBinario<T>* hijoDerecho;

public:

	/**
	 * Postcondiciones: El nodo queda creado sin dato ni hijos.
	 */
	NodoArbolBinario(){
		this->hijoIzquierdo = 0;
		this->hijoDerecho = 0;
	}

	/**
	 * Postcondiciones: El nodo y sus hijos quedan destruidos.
	 *                  En caso de que el dato se aun puntero
	 *                  no se lo deletea.
	 */
	~NodoArbolBinario(){
		if(this->getHijoIzquierdo() != 0 && this->getHijoIzquierdo() != this){
			delete this->getHijoIzquierdo();
		}
		if(this->getHijoDerecho() != 0 && this->getHijoDerecho() != this){
			delete this->getHijoDerecho();
		}
	}

	/**
	 * Postcondiciones: Se crea un nodo con los mismos datos
	 *                  e hijos que otroNodo.
	 */
	NodoArbolBinario(const NodoArbolBinario<T> &otroNodo){
		this->dato = otroNodo.dato;

		if(otroNodo.hijoIzquierdo != 0){
			NodoArbolBinario<T> *nodo = new NodoArbolBinario<T>(*(otroNodo.hijoIzquierdo));
			this->hijoIzquierdo = nodo;
		}

		if(otroNodo.hijoDerecho != 0){
			NodoArbolBinario<T> *nodo = new NodoArbolBinario<T>(*(otroNodo.hijoDerecho));
			this->hijoDerecho = nodo;
		}
	}

	/**
	 * Precondiciones: otroNodo no debe ser hijo un hijo.
	 * Postcondiciones: El nodo queda igual a otroNodo.
	 */
	NodoArbolBinario<T>& operator=(const NodoArbolBinario<T> &otroNodo){
		if(this != &otroNodo){
			if(this->hijoDerecho != 0){
				delete this->hijoDerecho;
				this->hijoDerecho = 0;
			}
			if(otroNodo.hijoDerecho != 0){
				NodoArbolBinario<T> *nodo = new NodoArbolBinario<T>(*(otroNodo.hijoDerecho));
				this->hijoDerecho = nodo;
			}

			if(this->hijoIzquierdo != 0){
				delete this->hijoIzquierdo;
				this->hijoIzquierdo = 0;
			}
			if(otroNodo.hijoIzquierdo != 0){
				NodoArbolBinario<T> *nodo = new NodoArbolBinario<T>(*(otroNodo.hijoIzquierdo));
				this->hijoIzquierdo = nodo;
			}
		}

		return (*this);
	}

	/**
	 * Postcondiciones: El dato del nodo queda seteado con el indicado.
	 */
	void setDato(T nuevoDato){
		this->dato = nuevoDato;
	}

	/**
	 * Postcondiciones: Retorna el dato.
	 */
	T getDato(){
		return this->dato;
	}

	/**
	 * Postcondiciones: El hijo izquierdo queda seteado con el indicado.
	 *                  Si ya tenia hijo izquierdo este se elimina.
	 */
	void setHijoIzquierdo(NodoArbolBinario<T> *nuevoHijoIzquierdo){
		if(this->getHijoIzquierdo() != 0){
			delete this->getHijoIzquierdo();
		}
		this->hijoIzquierdo = nuevoHijoIzquierdo;
	}

	/**
	 * Postcondicones: Retorna un puntero al hijo izquierdo, o NULL en caso
	 *                 de que no tenga.
	 */
	NodoArbolBinario<T>* getHijoIzquierdo(){
		return this->hijoIzquierdo;
	}

	/**
	 * Postcondiciones: El hijo derecho queda seteado con el indicado.
	 *                  Si ya tenia hijo derecho este se elimina.
	 */
	void setHijoDerecho(NodoArbolBinario<T> *nuevoHijoDerecho){
		if(this->getHijoDerecho() != 0){
			delete this->getHijoDerecho();
		}
		this->hijoDerecho = nuevoHijoDerecho;
	}

	/**
	 * Postcondicones: Retorna un puntero al hijo derecho, o NULL en caso
	 *                 de que no tenga.
	 */
	NodoArbolBinario<T>* getHijoDerecho(){
		return this->hijoDerecho;
	}

};

#endif /* __NODO_ARBOL_BINARIO_H__ */
